#pragma once

#include "log_functor.hpp"
#include "functor.hpp"
#include "allocator.hpp"
#include "reverse_iterator.hpp"

namespace zuck
{
	template<typename Vector>
	class _VectorConstIterator {
	private:
		using _Self = _VectorConstIterator<Vector>;
	public:
		using value_type		= typename Vector::value_type;
		using pointer           = typename Vector::const_pointer;
		using reference			= typename Vector::const_reference;
		using difference_type   = typename Vector::difference_type;
		using iterator_category = ::zuck::random_access_iterator_tag;
	private:
		pointer	_m_iter;
		pointer _m_first;
		pointer _m_last;
	public:
		ZCONSTEXPR explicit _VectorConstIterator(pointer iter, pointer first, pointer last)
			: _m_iter(iter), _m_first(first), _m_last(last) {}

		ZCONSTEXPR _VectorConstIterator(const _Self& other)
			: _m_iter(other._m_iter), _m_first(other._m_first)
            , _m_last(other._m_last) {}

		ZCONSTEXPR _VectorConstIterator(_Self&& other)noexcept
			: _m_iter(other._m_iter), _m_first(other._m_first)
            , _m_last(other._m_last)
		{
			other._m_iter  = null;
			other._m_first = null;
			other._m_last  = null;
		}

		ZCONSTEXPR virtual ~_VectorConstIterator()
		{
			_m_iter  = null;
			_m_first = null;
			_m_last  = null;
		}

		[[nodiscard]] ZCONSTEXPR pointer get_unwrapped()const
		{
			return _m_iter;
		}

		ZCONSTEXPR _VectorConstIterator& operator=(const _Self& other)
		{
			_m_iter  = other._m_iter;
			_m_first = other._m_first;
			_m_last  = other._m_last;
			return *this;
		}

		ZCONSTEXPR _VectorConstIterator& operator=(_Self&& other)noexcept
		{
			_m_iter  = other._m_iter;
			_m_first = other._m_first;
			_m_last  = other._m_last;
			other._m_iter  = null;
			other._m_first = null;
			other._m_last  = null;
			return *this;
		}

		[[nodiscard]] ZCONSTEXPR pointer operator->()const noexcept
		{
			if constexpr (debug_) {
				if (!_m_iter || _m_iter < _m_first || _m_iter >= _m_last) {
					throw ::std::out_of_range{"Segmentfault: invalid iter address !"};
				}
			}
			return _m_iter;
		}

		[[nodiscard]] ZCONSTEXPR reference operator*()const noexcept
		{
			if constexpr (debug_) {
				if (!_m_iter || _m_iter < _m_first || _m_iter >= _m_last) {
					throw ::std::out_of_range{"Segmentfault: invalid iter address !"};
				}
			}
			return *_m_iter;
		}

		ZCONSTEXPR _VectorConstIterator& operator++()noexcept
		{
			if constexpr (debug_) {
				if (_m_iter < _m_first || _m_iter >= _m_last) {
					throw ::std::out_of_range{"Segmentfault: can not referenced end vector iterator !"};
				}
			}
			++_m_iter;
			return *this;
		}

		ZCONSTEXPR _VectorConstIterator operator++(int)noexcept
		{
			auto _Tmp = *this;
			++(*this);
			return _Tmp;
		}

		ZCONSTEXPR _VectorConstIterator& operator+=(const difference_type step)noexcept
		{
			if constexpr (debug_) {
				auto const _Size = _m_last - _m_iter;
				if (_Size < step) {
					throw ::std::out_of_range{"Segmentfault: step too long !"};
				}
			}
			_m_iter += step;
			return *this;
		}

		[[nodiscard]] ZCONSTEXPR _VectorConstIterator operator+(const difference_type step)const noexcept
		{
			auto tmp = *this;
			return tmp += step;
		}

		[[nodiscard]] ZCONSTEXPR reference operator[](const difference_type ind)const noexcept
		{
			return *(*this + ind);
		}

		ZCONSTEXPR _VectorConstIterator& operator--()noexcept
		{
			if constexpr (debug_) {
				if (_m_iter < _m_first || _m_iter >= _m_last) {
					throw ::std::out_of_range{"Segmentfault: can not referenced rend vector iterator"};
				}
			}
			--_m_iter;
			return *this;
		}

		ZCONSTEXPR _VectorConstIterator operator--(int)noexcept
		{
			auto _Tmp = *this;
			--(*this);
			return _Tmp;
		}

		ZCONSTEXPR _VectorConstIterator& operator-=(const difference_type step)noexcept
		{
			if constexpr (debug_) {
				auto const _Size = _m_iter - _m_first;
				if (_Size < step) {
					throw ::std::out_of_range{"Segmentfault: step too long !"};
				}
			}
			_m_iter -= step;
			return *this;
		}

		[[nodiscard]] ZCONSTEXPR _VectorConstIterator operator-(const difference_type step)const noexcept
		{
			auto tmp = *this;
			return tmp -= step;
		}

		[[nodiscard]] ZCONSTEXPR difference_type operator-(const _Self& other)const noexcept
		{
			return static_cast<difference_type>(_m_iter - other._m_iter);
		}

		template<typename T, typename Iterator>
		[[nodiscard]] ZCONSTEXPR friend difference_type operator-(T* ptr, const Iterator& iter)
		{
			return static_cast<difference_type>(ptr - iter._m_iter);
		}

		[[nodiscard]] ZCONSTEXPR difference_type operator-(pointer iter)const noexcept
		{
			return static_cast<difference_type>(_m_iter - iter);
		}

		[[nodiscard]] ZCONSTEXPR bool operator==(const _Self& other)const noexcept
		{
			return static_cast<bool>(_m_iter == other._m_iter);
		}

		[[nodiscard]] ZCONSTEXPR bool operator!=(const _Self& other)const noexcept
		{
			return static_cast<bool>(_m_iter != other._m_iter);
		}

		[[nodiscard]] ZCONSTEXPR bool operator<(const _Self& other)const noexcept
		{
			return static_cast<bool>(_m_iter < other._m_iter);
		}

		[[nodiscard]] ZCONSTEXPR bool operator<=(const _Self& other)const noexcept
		{
			return static_cast<bool>(_m_iter <= other._m_iter);
		}

		[[nodiscard]] ZCONSTEXPR bool operator>(const _Self& other)const noexcept
		{
			return static_cast<bool>(_m_iter > other._m_iter);
		}

		[[nodiscard]] ZCONSTEXPR bool operator>=(const _Self& other)const noexcept
		{
			return static_cast<bool>(_m_iter >= other._m_iter);
		}
	};
	

	template<typename Vector>
	class _VectorIterator : public _VectorConstIterator<Vector> 
	{
	private:
		using _Base	= _VectorConstIterator<Vector>;
		using _Self	= _VectorIterator<Vector>;
	public:
		using value_type		= typename _Base::value_type;
		using pointer			= value_type*;
        using const_pointer     = const value_type*;
		using reference			= value_type&;
		using difference_type	= typename _Base::difference_type;
        using iterator_category = typename _Base::iterator_category;
	public:
		ZCONSTEXPR explicit _VectorIterator(pointer iter, pointer first, pointer last)
			: _Base(iter, first, last) {}

		ZCONSTEXPR _VectorIterator(const _VectorIterator& other)
			: _Base(other) {}

		ZCONSTEXPR _VectorIterator(_VectorIterator&& other)noexcept
			: _Base(::zuck::move(other)) {}

		ZCONSTEXPR _Self& operator=(const _Self& other)
		{
			_Base::operator=(other);
			return *this;
		}

		ZCONSTEXPR _Self& operator=(_Self&& other)noexcept
		{
			_Base::operator=(::zuck::move(other));
			return *this;
		}

		[[nodiscard]] ZCONSTEXPR reference operator*()noexcept
		{
			return const_cast<reference>(_Base::operator*());
		}

		[[nodiscard]] ZCONSTEXPR pointer operator->()noexcept
		{
			return const_cast<pointer>(_Base::operator->());
		}

		ZCONSTEXPR _Self& operator++()noexcept
		{
			_Base::operator++();
			return *this;
		}

		ZCONSTEXPR _Self operator++(int)noexcept
		{
			auto _Tmp = *this;
			_Base::operator++();
			return _Tmp;
		}

		ZCONSTEXPR _Self& operator--()noexcept
		{
			_Base::operator--();
			return *this;
		}

		ZCONSTEXPR _Self operator--(int)noexcept
		{
			auto _Tmp = *this;
			_Base::operator--();
			return _Tmp;
		}

		ZCONSTEXPR _Self& operator+=(const difference_type _Step)noexcept
		{
			_Base::operator+=(_Step);
			return *this;
		}

		[[nodiscard]] ZCONSTEXPR _Self operator+(const difference_type _Step)noexcept
		{
			auto _Tmp = *this;
			return _Tmp += _Step;
		}

		[[nodiscard]] ZCONSTEXPR reference operator[](const difference_type _Ind)const noexcept
		{
			return const_cast<reference>(_Base::operator[](_Ind));
		}

		ZCONSTEXPR _Self& operator-=(const difference_type _Step)noexcept
		{
			_Base::operator-=(_Step);
			return *this;
		}

		[[nodiscard]] ZCONSTEXPR _Self operator-(const difference_type _Step)noexcept
		{
			auto _Tmp = *this;
			return _Tmp -= _Step;
		}

		[[nodiscard]] ZCONSTEXPR difference_type operator-(const _Self& other)const noexcept
		{
			return _Base::operator-(other);
		}

		[[nodiscard]] ZCONSTEXPR difference_type operator-(const_pointer iter)const noexcept
		{
			return _Base::operator-(iter);
		}
	};


	template<typename T, typename Alloc = zuck::allocator<T>>
	class vector {
		static_assert(
			zuck::is_same_v<typename zuck::remove_cv_t<T>, T>,
			"template parameter \"T\" could not be both voltaile and constnat type");
	private:
		using _Self     = vector<T, Alloc>;
		using _Alty_tts = zuck::allocator_traits<Alloc>;
	public:
		using value_type	  = typename _Alty_tts::value_type;
		using pointer		  = typename _Alty_tts::pointer;
		using const_pointer	  = typename _Alty_tts::const_pointer;
		using reference		  = typename _Alty_tts::reference;
		using allocator_type  = typename _Alty_tts::allocator_type;
		using const_reference = typename _Alty_tts::const_reference;
		using size_type		  = typename _Alty_tts::size_type;
		using difference_type = typename _Alty_tts::difference_type;
	public:
		using iterator				 = _VectorIterator<vector<T, Alloc>>;
		using const_iterator		 = _VectorConstIterator<vector<T, Alloc>>;
		using reverse_iterator		 = zuck::reverse_iterator<iterator>;
		using const_reverse_iterator = zuck::reverse_iterator<const_iterator>;
	private:
		pointer	_m_start;
		pointer	_m_last;
		pointer	_m_end;
		Alloc alloc{};
	public:
		ZCONSTEXPR vector() : _m_start(), _m_last(), _m_end() {}

		ZCONSTEXPR vector(const size_type new_size)
			: _m_start(), _m_last(), _m_end()
		{
			__move_construct_n__(new_size, T{});
		}

		ZCONSTEXPR explicit vector(const size_type new_size, const T& elem)
			: _m_start(), _m_last(), _m_end()
		{
			__copy_construct_n__(new_size, elem);
		}

		ZCONSTEXPR explicit vector(const size_type new_size, T&& elem)
			: _m_start(), _m_last(), _m_end()
		{
			__move_construct_n__(new_size, zuck::move(elem));
		}

		ZCONSTEXPR vector(std::initializer_list<T> data)
			: _m_start(), _m_last(), _m_end()
		{
			__construct_range(data.begin(), data.end());
		}

		template<typename InputIterator,
			zuck::enable_if_t<!is_integral_v<InputIterator> && zuck::is_input_iterator_v<InputIterator>, int> = 0>
		ZCONSTEXPR explicit vector(InputIterator first, InputIterator last)
			: _m_start(), _m_last(), _m_end()
		{ 
			__construct_range(first, last);
		}

		template<typename InputIterator,
			zuck::enable_if_t<!is_integral_v<InputIterator> && zuck::is_input_iterator_v<InputIterator>, int> = 0>
		ZCONSTEXPR explicit vector(InputIterator first, InputIterator last, Alloc al)
			: _m_start(), _m_last(), _m_end(), alloc(al)
		{
			__construct_range(first, last);
		}

		ZCONSTEXPR explicit vector(const _Self& srcData, size_type begin, const size_type end)
			: _m_start(), _m_last(), _m_end()
		{
			__construct_range(srcData, begin, end);
		}

		ZCONSTEXPR vector(const _Self& other)
			: _m_start(), _m_last(), _m_end()
		{
			__construct_range(other.begin(), other.end(), Alloc{});
		}

		ZCONSTEXPR vector(_Self&& other)noexcept
			: _m_start(other._m_start), _m_last(other._m_last)
			, _m_end(other._m_end)
		{
			other._m_start = null;
			other._m_last  = null;
			other._m_end   = null;
		}

		ZCONSTEXPR ~vector()
		{
			__destroy();
		}

	public:
		ZCONSTEXPR void assign(const size_type _Newsize, const_reference val)
		{
			auto const _Oldcapacity = capacity();

			if (_Newsize > _Oldcapacity) {
				if (_Newsize > max_size()) {
					return;
				}
				_Alty_tts::destruct_range(_m_start, _m_last);
				alloc.deallocate(_m_start, _Oldcapacity);
				_m_start = alloc.allocate(_Newsize);
				_m_end   = _m_start + _Newsize;

				for (_m_last = _m_start; _m_last != _m_end; ++_m_last) {
					_Alty_tts::construct(_m_last, val);
				}
				return;
			}
			auto const _Oldsize = size();
			if (_Newsize > _Oldsize) {
				_m_last += (_Newsize - _Oldsize);
				for (auto* proxy = _m_start; proxy != _m_last; ++proxy) {
					*proxy = val;
				}
				return;
			}
			_m_last -= (_Oldsize - _Newsize);
			for (auto* proxy = _m_start; proxy != _m_last; ++proxy) {
				*proxy = val;
			}
		}

		ZCONSTEXPR void assign(std::initializer_list<T> data)
		{
			__assign_range(data.begin(), data.end());
		}

        template<typename InputIterator, 
            zuck::enable_if_t<zuck::is_input_iterator_v<InputIterator>, int> = 0>
		ZCONSTEXPR void assign(InputIterator Begin, InputIterator End)
		{
			__assign_range(Begin, End);
		}

		[[nodiscard]] ZCONSTEXPR reference at(const size_type _Idx)noexcept
		{
			if (out_of_range(_Idx, size())) {
				throw std::out_of_range{};
			}
			return *(_m_start + _Idx);
		}

		[[nodiscard]] ZCONSTEXPR reference at(const size_type _Idx)const noexcept
		{
			if (out_of_range(_Idx, size())) {
				throw std::out_of_range{};
			}
			return *(_m_start + _Idx);
		}

		ZCONSTEXPR void clear()noexcept
		{
			_Alty_tts::destruct_range(_m_start, _m_last);
			_m_last = _m_start;
		}

		[[nodiscard]] ZCONSTEXPR pointer data()noexcept
		{
			return _m_start ? _m_start : null;
		}

		[[nodiscard]] ZCONSTEXPR const_pointer data()const noexcept
		{
			return _m_start ? _m_start : null;
		}

		[[nodiscard]] ZCONSTEXPR reference front()noexcept
		{
			return *_m_start;
		}

		[[nodiscard]] ZCONSTEXPR const_reference front()const noexcept
		{
			return *_m_start;
		}

		[[nodiscard]] ZCONSTEXPR reference back()noexcept
		{
			return *(_m_last - 1);
		}

		[[nodiscard]] ZCONSTEXPR const_reference back()const noexcept
		{
			return *(_m_last - 1);
		}

		[[nodiscard]] ZCONSTEXPR allocator_type get_allocator()const noexcept
		{
			return Alloc{};
		}

		ZCONSTEXPR bool pop_back()
		{
			if (empty()) { 
				return false; 
			}
			_Alty_tts::destruct(*_m_last);
			--_m_last;
			return true;
		}

		ZCONSTEXPR void reserve(const size_type new_capacity)
		{
			if (new_capacity > capacity()) {
				if (new_capacity > max_size()) {
					throw ::std::bad_array_new_length{};
				}
				__realloc(new_capacity);
			}
		}

		ZCONSTEXPR void resize(const size_type __New)
		{
			__resize(__New, T{});
		}

		ZCONSTEXPR void resize(const size_type __New, const T& val)
		{
			__resize(__New, val);
		}

		[[nodiscard]] ZCONSTEXPR size_type size()const noexcept
		{
			return static_cast<size_type>(_m_last - _m_start);
		}

		[[nodiscard]] ZCONSTEXPR size_type max_size()const noexcept
		{
			return _Alty_tts::max_size();
		}

		[[nodiscard]] ZCONSTEXPR bool empty()const noexcept
		{
			return static_cast<bool>(_m_last == _m_start || !_m_start);
		}

		[[nodiscard]] ZCONSTEXPR bool no_unused()const noexcept
		{ 
			return static_cast<bool>((_m_last == _m_end) && !static_cast<bool>(!_m_last));
		}

		template<typename ...Args>
		[[nodiscard]] ZCONSTEXPR iterator emplace(const_iterator Wh, Args&&... args)
		{
			auto const _Oldsize = size();
			auto* const _Ptr	= Wh.get_unwrapped();

			if (!_Oldsize && !_m_start) {
				__alloc_for_none(zuck::forward<Args>(args)...);
				_Alty_tts::construct(_m_start, zuck::forward<Args>(args)...);
				return iterator(_m_start, _m_start, _m_last);
			}
			auto _Dis = _Oldsize - (_Ptr - _m_start);
			if (_m_last == _m_end) {
				auto const _oldcapacity = capacity();
				__verify_size(_oldcapacity + 1);
				__expand_capacity();
			}
			auto* _Pos = _m_last;
			for (; _Dis; --_Pos, --_Dis) {
				_Alty_tts::construct(_Pos, T(*(_Pos - 1)));
			}
			_Alty_tts::construct(_Pos, zuck::forward<Args>(args)...);
			++_m_last;

			return iterator(_Pos, _m_start, _m_last);
		}

		template<typename ...Args>
		[[nodiscard]] ZCONSTEXPR reference emplace_back(Args&&... args)
		{
			if (!no_unused()) {
				return __emplace_with_unused_capacity(zuck::forward<Args>(args)...);
			}
			return __emplace_with_realloc_mem(zuck::forward<Args>(args)...);
		}

		[[nodiscard]] ZCONSTEXPR size_type capacity()const noexcept
		{
			return static_cast<size_type>(_m_end - _m_start);
		}

		[[nodiscard]] ZCONSTEXPR size_type unused_capacity()const noexcept
		{
			return static_cast<size_type>(_m_end - _m_last);
		}

		ZCONSTEXPR iterator insert(const_iterator wh, const T& val)
		{
			emplace(wh, val);
		}

		ZCONSTEXPR void insert(const_iterator wh, T&& val)
		{
			emplace(wh, ::zuck::move(val));
		}

		ZCONSTEXPR void push_back(const T& val)
		{
			emplace_back(val);
		}

		ZCONSTEXPR void push_back(T&& val)
		{
			emplace_back(::zuck::move(val));
		}

		ZCONSTEXPR void swap(_Self& other)noexcept
		{
			if (_m_start != other._m_start) {
				auto _Tmp = ::zuck::move(other);
				other     = ::zuck::move(*this);
				*this     = ::zuck::move(_Tmp);
			}
		}

		[[nodiscard]] ZCONSTEXPR iterator begin()noexcept
		{
			return iterator(_m_start, _m_start, _m_last);
		}

		[[nodiscard]] ZCONSTEXPR const_iterator begin()const noexcept
		{
			return const_iterator(_m_start, _m_start, _m_last);
		}

		[[nodiscard]] ZCONSTEXPR const_iterator cbegin()const noexcept
		{
			return const_iterator(_m_start, _m_start, _m_last);
		}

		[[nodiscard]] ZCONSTEXPR iterator end()noexcept
		{ 
			return iterator(_m_last, _m_start, _m_last);
		}

		[[nodiscard]] ZCONSTEXPR const_iterator end()const noexcept
		{
			return const_iterator(_m_last, _m_start, _m_last);
		}

		[[nodiscard]] ZCONSTEXPR const_iterator cend()const noexcept
		{
			return const_iterator(_m_last, _m_start, _m_last);
		}

		[[nodiscard]] ZCONSTEXPR reverse_iterator rbegin()noexcept
		{
			return reverse_iterator(_m_last - 1, _m_start, _m_last); 
		}

		[[nodiscard]] ZCONSTEXPR const_reverse_iterator rbegin()const noexcept
		{
			return const_reverse_iterator(_m_last - 1, _m_start, _m_last); 
		}

		[[nodiscard]] ZCONSTEXPR const_reverse_iterator crbegin()const noexcept
		{
			return const_reverse_iterator(_m_last - 1, _m_start, _m_last); 
		}

		[[nodiscard]] ZCONSTEXPR reverse_iterator rend()noexcept
		{
			return reverse_iterator(_m_start - 1, _m_start, _m_last); 
		}

		[[nodiscard]] ZCONSTEXPR const_reverse_iterator rend()const noexcept
		{
			return const_reverse_iterator(_m_start - 1, _m_start, _m_last); 
		}

		[[nodiscard]] ZCONSTEXPR const_reverse_iterator crend()const noexcept
		{
			return const_reverse_iterator(_m_start - 1, _m_start, _m_last); 
		}

		ZCONSTEXPR vector& operator=(const _Self& other)
		{
			return __operator_assign(other); 
		}

		ZCONSTEXPR vector& operator=(_Self&& other)noexcept
		{
			return __move_construct(::zuck::move(other)); 
		}

		[[nodiscard]] ZCONSTEXPR reference operator[](const size_type _Index)noexcept
		{
			if constexpr (debug_) {
				if (out_of_range(_Index, size())) {
					throw ::std::out_of_range{};
				}
			}
			return *(_m_start + _Index);
		}

		[[nodiscard]] ZCONSTEXPR const_reference operator[](const size_type _Index)const noexcept
		{
			if constexpr (debug_) {
				if (out_of_range(_Index, size())) {
					throw ::std::out_of_range{};
				}
			}
			return *(_m_start + _Index);
		}

		[[nodiscard]] ZCONSTEXPR _Self operator()(difference_type begin, const difference_type end)const noexcept
		{
			ZCONST bool reverse_flag = !static_cast<bool>((begin ^ -1) ^ (end ^ -1));
			if (reverse_flag) {
				return _Self(crbegin(), crend());
			}

			auto const _Dis = zuck::distance(begin, end);
			auto const _Size = size();
			_Self resVector(_Dis < _Size ? _Dis : _Size);

			for (; begin != end; ++begin) {
				resVector[begin] = *(_m_start + begin);
			}
			return resVector;
		}

		[[nodiscard]] ZCONSTEXPR _Self operator()(const int pos)const
		{
			bool ZCONST isFullySelf = static_cast<bool>(pos == 58);
			bool ZCONST isReverse   = static_cast<bool>(pos == -1);

			if ZCONSTEXPR (isFullySelf) {
				return *this;
			}
			if ZCONSTEXPR (isReverse) {
				return _Self{ crbegin(), crend() };
			}
			return _Self{};
		}

		[[nodiscard]] ZCONSTEXPR bool operator==(const _Self& other)const noexcept
		{
			return static_cast<bool>(size() == other.size() && 
				   __equal_with(other, zuck::equal_to<T>{}));
		}

		[[nodiscard]] ZCONSTEXPR bool operator!=(const _Self& other)const noexcept
		{
			return static_cast<bool>(size() != other.size() || 
				   __not_equal_with(other, zuck::not_equal_to<T>{}));
		}

	private:
		ZCONSTEXPR _Self& __operator_assign(const _Self& other)
		{
			_m_last = _m_start;
			for (const auto& __elem : other) {
				push_back(__elem);
			}
			return *this;
		}

		ZCONSTEXPR void __allocate_mem(const zuck::size_t count)
		{
			_m_start = alloc.allocate(count);
			_m_end   = _m_start + count;
		}

		ZCONSTEXPR void __copy_construct_n__(const size_type _Size, const T& val)
		{
			__allocate_mem(_Size);
			for (_m_last = _m_start; _m_last != _m_end; ++_m_last) {
				_Alty_tts::construct(_m_last, val);
			}
		}

		ZCONSTEXPR void __move_construct_n__(const size_type size, T&& val)
		{
			__allocate_mem(size);
			for (_m_last = _m_start; _m_last != _m_end; ++_m_last) {
				_Alty_tts::construct(_m_last, zuck::move(val));
			}
		}

		ZCONSTEXPR void __destroy()
		{
			_Alty_tts::destruct_range(_m_start, _m_end);
			alloc.deallocate(_m_start, capacity());
		}

		template<typename ...Args>
		ZCONSTEXPR reference __emplace_with_unused_capacity(Args&&... args)
		{
			_Alty_tts::construct(_m_last, zuck::forward<Args>(args)...);
			T& _result = *_m_last;
			++_m_last;
			return _result;
		}

		template<typename ...Args>
		ZCONSTEXPR void __alloc_for_none(Args&&... args)
		{
			_m_start = alloc.allocate(1);
			_m_end = _m_start + 1;
			_m_last = _m_start + 1;
			_Alty_tts::construct(_m_start, zuck::forward<Args>(args)...);
		}

		template<typename ...Args>
		ZCONSTEXPR reference __emplace_with_realloc_mem(Args&&... args)
		{
			if (_m_start) {
				__expand_capacity();
				_Alty_tts::construct(_m_last++, zuck::forward<Args>(args)...);
				return *(_m_last - 1);
			}
			__alloc_for_none(zuck::forward<Args>(args)...);
			return *_m_start;
		}

		template<typename _Pred>
		[[nodiscard]] ZCONSTEXPR bool __equal_with(const _Self& other, _Pred _Pr)const noexcept
		{
			auto& _MyFirst      = begin();
			auto const& _MyLast = end();
			auto& _OFirst       = other.begin();
			auto const& _OLast  = other.end();

			for (; _MyFirst != _MyLast && _OFirst != _OLast; ++_MyFirst, ++_OLast) {
				if (!_Pr(*_MyFirst, *_OLast)) {
					return false;
				}
			}
			return true;
		}

		template<typename _Pred>
		[[nodiscard]] ZCONSTEXPR bool __not_equal_with(const _Self& other, _Pred _Pr)const noexcept
		{
			auto _MyFirst      = begin();
			auto const _MyLast = end();
			auto _OFirst       = other.begin();
			auto const _OLast  = other.end();

			for (; _MyFirst != _MyLast && _OFirst != _OLast; ++_MyFirst, ++_OLast) {
				if (_Pr(*_MyFirst, *_OLast)) {
					return true;
				}
			}
			return false;
		}

        [[nodiscard]] ZCONSTEXPR size_type __get_capacity(const size_type _OldCapacity)const noexcept
		{
			return ((_OldCapacity << 1) + (_OldCapacity >> 1));
		}

		ZCONSTEXPR void __expand_capacity()
		{
			auto* _Proxy = _m_start;

			auto const _OldCapacity = capacity();
			auto const _NewCapacity	= __get_capacity(_OldCapacity);

			_m_start = alloc.allocate(_NewCapacity);
			_Alty_tts::construct_range(_m_start, _m_start + _OldCapacity, 
				                       _Proxy, _Proxy + _OldCapacity);
			_Alty_tts::destruct_range(_Proxy, _Proxy + _OldCapacity);
			alloc.deallocate(_Proxy, _OldCapacity);
			_m_end  = zuck::address_of(_m_start[_NewCapacity - 1]) + 1;
			_m_last = zuck::address_of(_m_start[_OldCapacity - 1]) + 1;
		}

		ZCONSTEXPR _Self& __move_construct(_Self&& other)noexcept
		{
			__destroy_if_not_empty();

			_m_start = other._m_start;
			_m_last  = other._m_last;
			_m_end   = other._m_end;
			other._m_start = null;
			other._m_last  = null;
			other._m_end   = null;
			return *this;
		}

		ZCONSTEXPR void __realloc(const size_type _NewCapacity)
		{
			auto const _Oldsize     = size();
			auto const _OldCapacity = capacity();
			
			auto* _Proxy = _m_start;
			_m_start = alloc.allocate(_NewCapacity);
			_m_last = zuck::address_of(_m_start[_Oldsize]);
			_m_end	= zuck::address_of(_m_start[_NewCapacity]);

			_Alty_tts::construct_range(_m_start, _m_last, _Proxy, _Proxy + _Oldsize);
			_Alty_tts::destruct_range(_Proxy, _Proxy + _Oldsize);

			if (_Proxy) {
				alloc.deallocate(_Proxy, _OldCapacity);
			}
		}

		ZCONSTEXPR void __push_elem(const T& val)
		{
			if (!no_unused()) {
				__emplace_with_unused_capacity(val);
				return;
			}
			__emplace_with_realloc_mem(val);
		}

		template<typename PointerType>
		ZCONSTEXPR void __assign_range(PointerType first, PointerType last)
		{
			auto const _Last = last;
			auto const _Newsize		= zuck::distance(first, last);
			auto const _Oldcapacity = capacity();

			if (_Oldcapacity < _Newsize) {
				alloc.deallocate(_m_start, _Oldcapacity);
				_m_start = alloc.allocate(_Newsize);
				_m_last	= zuck::address_of(_m_start[_Newsize - 1]) + 1;
				_m_end	= zuck::address_of(_m_start[_Newsize - 1]) + 1;
				__construct_range(_m_start, _m_last, first, last);
				return;
			}

			auto _Next = _m_start;
			auto _First = first;
			for (; _First != _Last && _Next != _m_last; ++_First, ++_Next) {
				*_Next = *_First;
			}

			_Alty_tts::destruct_range(_Next, _m_last);
			_m_last = _Next;
			for (; _First != _Last; ++_First) {
				__push_elem(*_First);
			}
		}

		ZCONSTEXPR void __construct_range
		(const _Self& sourceData, size_type Begin, const size_type End)
		{
			auto const Newsize = zuck::distance(Begin, End);
			_m_start = alloc.allocate(Newsize);
			_m_end   = _m_start + Newsize;
			_m_last  = _m_start;
			
			for (; _m_last != _m_end && Begin != End; ++_m_last, ++Begin) {
				_Alty_tts::construct(_m_last, sourceData[Begin]);
			}
		}

		ZCONSTEXPR void __resize(const size_type _new, const T& val)
		{
			auto const _Oldsize		= size();
			auto const _Oldcapacity = capacity();
			
			if (_new > _Oldcapacity) {
				__verify_size(_new);
				auto* _Proxy = _m_start;
				_m_start = alloc.allocate(_new);
				_Alty_tts::construct_range(_m_start, _m_start + _Oldsize, _Proxy, _Proxy + _Oldsize);
				_Alty_tts::construct_range(_m_start + _Oldsize, _m_start + _new, val);
				_m_last	= zuck::address_of(_m_start[_new - 1]) + 1;
				_m_end	= zuck::address_of(_m_start[_new - 1]) + 1;
				_Alty_tts::destruct_range(_Proxy, _Proxy + _Oldcapacity);
				alloc.deallocate(_Proxy, _Oldcapacity);
				return;
			}
			else if (_Oldsize < _new) {
				_m_last += _new - _Oldsize;
				_Alty_tts::construct_range(_m_start + _Oldsize, _m_last, val);
				return;
			}
			auto _Destructsize = _Oldsize - _new;
			for (; _Destructsize; --_Destructsize) {
				_Alty_tts::destruct(*(_m_last - 1));
				--_m_last;
			}
		}
		
		ZCONSTEXPR void __destroy_if_not_empty()
		{
			if (!empty()) {
				__destroy();
			}
		}

		ZCONSTEXPR void __verify_size(const size_type _Newsize)
		{
			auto const _Max = max_size();
			if (_Newsize > _Max) {
				throw ::std::bad_array_new_length{"vector length too long !"};
			}
		}

		template<typename InputIterator>
		ZCONSTEXPR void __verify_range(InputIterator first, InputIterator last)
		{
			auto const _Newsize = zuck::distance(first, last);
			__verify_size(_Newsize);
		}
	};


	template<typename T, typename Alloc = allocator<T>>
	vector(::zuck::size_t, T) -> vector<T, Alloc>;

	template<typename T, typename Alloc = allocator<T>>
	vector(::std::initializer_list<T>) -> vector<T, Alloc>;

	template<typename T, typename Alloc = allocator<T>>
	vector(::std::initializer_list<T>, Alloc) -> vector<T, Alloc>;

	template<typename T, typename Alloc = allocator<T>>
	vector(const vector<T, Alloc>&) -> vector<T, Alloc>;

	template<typename T, typename Alloc = allocator<T>>
	vector(const vector<T, Alloc>&, Alloc) -> vector<T, Alloc>;

	template<typename T, typename Alloc = allocator<T>>
	vector(vector<T, Alloc>&&) -> vector<T, Alloc>;

	template<typename InputIterator, 
		typename T	   = ::zuck::iter_traits_t<InputIterator>,
		typename Alloc = ::zuck::allocator<T>,
		::zuck::enable_if_t<is_input_iterator_v<InputIterator>, int> = 0>
	vector(InputIterator, InputIterator) -> vector<T, Alloc>;

	template<typename InputIterator,
		typename T	   = ::zuck::iter_traits_t<InputIterator>,
		typename Alloc = ::zuck::allocator<T>,
		::zuck::enable_if_t<is_input_iterator_v<InputIterator>, int> = 0>
	vector(InputIterator, InputIterator, Alloc) -> vector<T, Alloc>;

	template<typename T, typename Alloc = ::zuck::allocator<T>>
	using ZVector = vector<T, Alloc>;
}// ::zuck::vector end

